package com.projetosi.web.server.sistema.sistema;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.projetosi.web.server.sistema.objetos.Mensagem;
import com.projetosi.web.server.sistema.objetos.Usuario;
import com.projetosi.web.server.sistema.util.MessageDateComparator;

/**
 * 
 * @author Felipe Jose, Filipe Alencar, Rodrigo de Brito, Thiago Goncalves, Victor Hugo Arcelino;
 *
 */
public class GerenciadorDeMensagens {
	
	private List<Mensagem> listaDeMensagens = new ArrayList<Mensagem>();
	private Map<String, String> idTopicos = new HashMap<String, String>();
	private static GerenciadorDeMensagens _gerenciador;
	
	public static GerenciadorDeMensagens getInstance(){
		return(_gerenciador == null)? _gerenciador = new GerenciadorDeMensagens(): _gerenciador;
	}
	
	/**
	 * Metodo para retornar todas as mensagens enviadas pelo usuario;
	 * @return Um ArrayList com  de todas as mensagens enviadas pelo usuario;
	 */
	public List<Mensagem> getMensagens(){
		return this.listaDeMensagens;
	}
	
	/**
	 * Metodo para retornar a variavel topicos;
	 * @return Um Mapa<String assunto, Array<Mensagens> mensagens> com os topicos relacionados
	 */
	public Map<String,String> getTopicos(){
		return this.idTopicos;
	}
	
	// -------------------------  NADA DE ORDENAPORDATA() DAQUI PRA CIMA ---------------------------
	
	/**
	 * Metodo para retornar as mensagens de determinado tipo;
	 * @param ehpadrao - Um boolean indicando se o usuario quer todas as mensagens padrão ou não;
	 * @param ListaDeMensagens - A lista de mensagens que se deseja pesquisar;
	 * @return Um ArrayList<Mensagem> contendo apenas as mensagens do tipo desejado; 
	 */
	public List<Mensagem> getMensagensPadrao(boolean ehpadrao, List<Mensagem> listaDeMensagens){
		
		List <Mensagem> listaComMensagensPadrao = new ArrayList<Mensagem>();
		
		if(!listaDeMensagens.isEmpty()){
			for(Mensagem mensagem: ordenaPorData(listaDeMensagens)){
				if(mensagem.isPadrao() == ehpadrao){
					listaComMensagensPadrao.add(mensagem);
				}
			}
		}
		
		return listaComMensagensPadrao;
	}
	
	// ------------------------------   OK PARA O METODO ACIMA ------------------------------------
	
	/**
	 * Metodo para retornar a uniao das mensagens enviadas e recebidas e ja ordenadas por data;
	 * @return Um ArrayList<Mensagem> com todas as mensagens que envolvem o usuario;
	 */
	public List<Mensagem> getTodasAsMensagens(Usuario user){
		List <Mensagem> listaComTodasAsMensagens = new ArrayList<Mensagem>();
		
		if(!listaDeMensagens.isEmpty()){
			for(Mensagem mensagem: listaDeMensagens){
				if(mensagem.getRemetente().equals(user) || mensagem.getDestinatario().equals(user))
					listaComTodasAsMensagens.add(mensagem);
			}
		}
		
		return ordenaPorData(listaComTodasAsMensagens);
	}
	
	public List<Mensagem> getTodasAsMensagens(){
		List <Mensagem> listaComTodasAsMensagens = new ArrayList<Mensagem>();
		
		if(!listaDeMensagens.isEmpty()){
			for(Mensagem mensagem: listaDeMensagens){
				listaComTodasAsMensagens.add(mensagem);
			}
		}
		
		return ordenaPorData(listaComTodasAsMensagens);
	}
	
	//------------------------------  OK PARA O METODO ACIMA -----------------------------------------
	
	

	/**
	 * Metodo para enviar uma mensagem;
	 * @param mensagem - A mensagem que se deseja enviar;
	 * @return A mensagem enviada;
	 */
	public String enviarMensagem(Mensagem mensagem){
		listaDeMensagens.add(mensagem);
		Integer id = gerarIdTopico();
		while (this.idTopicos.containsKey(id+"")){
			id = gerarIdTopico();
		}
		
		if(!idTopicos.containsValue(mensagem.getAssunto())){
			idTopicos.put(id+"", mensagem.getAssunto());
			return id+"";
		}else{
			for(String idTopico: idTopicos.keySet()){
				if(idTopicos.get(idTopico).equals(mensagem.getAssunto())){
					return idTopico;
				}
			}
		}
		return id+"";
		
	}
	
	public int gerarIdTopico(){
		Random rand = new Random();
		int id = 100000+rand.nextInt(899999);
		return id;
	}
	
	// ----------------------  METODO ACIMA OK  -----------------------------------------------------
	
	/**
	 * Metodo para ler uma mensagem;
	 * @param mensagem - A mensagem que se deseja ler;
	 */
	public void lerMensagem(Mensagem mensagem){
		StringBuffer sb = new StringBuffer();
		sb.append("De: " + mensagem.getRemetente().getNome());
		sb.append("\nAssunto: ");
		sb.append(mensagem.getAssunto());
		sb.append("\nMensagem: \n");
		sb.append(mensagem.getCorpoDaMensagem() + "\n");
		mensagem.setLida(true);
		System.out.println(sb.toString());
	}
	
	// -----------------------------   METODO ACIMA OK   ---------------------------------------
	
	/**
	 * Metodo para exibir, por ordem de envio, a caixa de entrada do usuario;
	 */
	public void exibirCaixaDeEntrada(Usuario user){
		StringBuffer sb = new StringBuffer();
		sb.append("\n------------------------   CAIXA DE ENTRADA   ---------------------------\n");
		for(Mensagem mensagem: ordenaPorData(listaDeMensagens)){
			if(mensagem.getDestinatario().equals(user))
			sb.append(mensagem.getRemetente().getNome() + "     |     " + mensagem.getAssunto() + "     |     " + mensagem.getDataDeEnvio().dataFormatada() + "\n");
		}
		System.out.println(sb.toString());
	}
	
	// -----------------------------  METODO ACIMA OK   -----------------------------------------
	
	/**
	 * Metodo para exibir, por ordem de envio, a caixa de saida do usuario;
	 */
	public void exibirCaixaDeSaida(Usuario user){
		StringBuffer sb = new StringBuffer();
		sb.append("\n------------------------   CAIXA DE SAIDA   ---------------------------\n");
		for(Mensagem mensagem: ordenaPorData(listaDeMensagens)){
			if(mensagem.getRemetente().equals(user))
			sb.append(mensagem.getDestinatario().getNome() + "     |     " + mensagem.getAssunto() + "     |     " + mensagem.getDataDeEnvio().dataFormatada() + "\n");
		}
		System.out.println(sb.toString());
	}
	
	//------------------------------  METODO ACIMA OK   ---------------------------------------------------
	
	/**
	 * Metodo auxiliar para ordenar as mensagens de uma lista pela data de envio(Última recebida = Primeira ;
	 * @param listaDeMensagens - Do tipo List<Mensagem>, eh uma lista com as mensagens
	 * que se deseja ordenar; 
	 * @return Um ArrayList<Mensagens> com todas as mensagens em ordem de envio;
	 */
	private List<Mensagem> ordenaPorData(List<Mensagem> listaDeMensagens) {
		
		List<Mensagem> ordenada = new ArrayList<Mensagem>();
		
		if(!listaDeMensagens.isEmpty()){
			
			for(int i=0; i < listaDeMensagens.size(); i++){
				ordenada.add(listaDeMensagens.get(i));
		}
			
		Collections.sort((ArrayList<Mensagem>) ordenada, new MessageDateComparator());
		}
		
		return (List<Mensagem>) ordenada;
	
	}
	
	// ---------------------------------- METODO ACIMA OK --------------------------------
		
	/**
	 * Metodo para organizar uma lista de mensagens em forma de mapa;
	 * @param listaDeMensagens - Uma lista com as mensagens que se deseja organizar;
	 * @return Um mapa contendo o assunto como chave e um array de mensagens como valor;
	 * @throws Exception Caso a lista esteja vazia uma excecao sera lancada;
	 */
	public Map<String, List<Mensagem>> organizarTopicos(List<Mensagem> listaDeMensagens) throws Exception{
		
		/*if(listaDeMensagens.isEmpty()){
			throw new Exception("Não há tópicos criados");  editar
		}*/
		
		Map<String, List<Mensagem>> topicosOrganizados = new HashMap<String, List<Mensagem>>();
		for(Mensagem mensagem: listaDeMensagens){
			List<Mensagem> valores = new ArrayList<Mensagem>();
			if(topicosOrganizados.containsKey(mensagem.getAssunto())){
				topicosOrganizados.get(mensagem.getAssunto()).add(mensagem);
			}	
			if(topicosOrganizados.containsKey(mensagem.getAssunto()) == false){
				topicosOrganizados.put(mensagem.getAssunto(), valores );
				topicosOrganizados.get(mensagem.getAssunto()).add(mensagem);
			}
		}		
		return topicosOrganizados;
	}
	
	// ----------------------------------  METODO ACIMA OK -------------------------------------
	
	/**
	 * Metodo para exibir os topicos de um mapa;
	 * @param topicos - Um mapa contendo o assunto como chave e o array como valor;
	 */
	public String lerTopicos(Map<String, List<Mensagem>> topicos, Usuario user){
		StringBuffer sb = new StringBuffer();
		
		List<Mensagem> mensagensMaisAntigas = new ArrayList<Mensagem>();
		List<Mensagem> auxiliar = new ArrayList<Mensagem>();
		
		//Vamos adicionar a mensagem mais antiga de determinado assunto a lista MensagensMaisAntigas
		for(String assunto: topicos.keySet()){
			auxiliar = ordenaPorData(topicos.get(assunto));
			mensagensMaisAntigas.add(auxiliar.get(auxiliar.size() -1));
		}
		
		//Vamos ordenar a mensagem da mais recente pra mais antiga
		//mensagensMaisAntigas = ordenaPorData(mensagensMaisAntigas);
		Collections.sort(mensagensMaisAntigas, new MessageDateComparator());
		//O topico mais antigo eh aquele que tem a mensagem mais antiga
		for(Mensagem mensagem: mensagensMaisAntigas){
			if(mensagem.getRemetente().equals(user) || mensagem.getDestinatario().equals(user))
				sb.append((mensagem.getAssunto() + "; "));
			}
		
		if (!sb.toString().isEmpty())
			return sb.toString().substring(0,sb.toString().length()-2);
		return sb.toString().substring(0,sb.toString().length());
	}
	
	// ------------------------  METODO ACIMA OK   -----------------------------------------
	
	/**
	 * Metodo para exibir as mensagens correspondentes a um assunto em ordem de acontecimento
	 * @param assunto - Uma String contendo o assunto desejado para se exibir as mensagens correspondentes
	 * @param topicos - Um mapa(string, list<mensagens>) que representa os tópicos e as mensagens existentes
	 */
	public String lerMensagensDeUmTopico(String idTopico) throws Exception{
		
		StringBuffer sb = new StringBuffer();
		if(idTopicos.containsKey(idTopico) == false){
			throw new Exception("Tópico inexistente");
		}
		else{
			ArrayList<Mensagem> lista = new ArrayList<Mensagem>();
			lista = (ArrayList<Mensagem>)(getTodasAsMensagens());
			Collections.reverse(lista);
			for(Mensagem m : lista)
				if(m.getAssunto().equals(idTopicos.get(idTopico)))
					sb.append(m.getCorpoDaMensagem()+ "; ");
		}
		return sb.toString().substring(0, sb.toString().length()-2);
	}

	public static void zerarGerenciador(){
		_gerenciador = null;
	}
}